package com.huaxin.device.service.impl;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.huaxin.device.dto.enums.AlarmType;
import com.huaxin.device.dto.request.DeviceAlarmCreateReqDTO;
import com.huaxin.device.dto.request.DeviceAlarmNotificationCreateReqDTO;
import com.huaxin.device.feignClients.SysFeignService;
import com.huaxin.device.models.*;
import com.huaxin.device.service.*;
import com.huaxin.feignclient.system.models.Family;
import com.huaxin.hxenum.enums.ComparisonOperator;
import com.huaxin.hxenum.enums.DataType;
import com.huaxin.hxenum.enums.EquipmentDataType;
import com.huaxin.hxenum.enums.NotificationType;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;

import static org.springframework.util.StringUtils.hasText;

@Service
@RequiredArgsConstructor
@Slf4j
public class AlarmDetectionServiceImpl implements AlarmDetectionService {

    private final DeviceAlarmConfigService deviceAlarmConfigService;
    private final AlarmThresholdTemplateService alarmThresholdTemplateService;
    private final AlarmThresholdRuleService alarmThresholdRuleService;
    //    private final DeviceReadingCircuitBreakerService deviceReadingCircuitBreakerService;
//    private final DeviceReadingEnvironmentService deviceReadingEnvironmentService;
    private final DeviceDataCollectionWideService deviceDataCollectionWideService;
    private final DeviceAlarmService deviceAlarmService;
    private final DeviceInstanceService deviceInstanceService;
    private final AlarmStateService alarmStateService;
    private final ObjectMapper objectMapper;
    private final AlarmMessageParameterExtractor alarmMessageParameterExtractor;
    private final DeviceAlarmNotificationService deviceAlarmNotificationService;
    private final SysFeignService sysFeignService;

    // 缓存覆盖规则（可扩展为 Redis）
    private final Map<String, String> overrideRuleCache = new ConcurrentHashMap<>();

    @Override
    public void detectAndAlert(String deviceId) {
        DeviceAlarmConfig config = deviceAlarmConfigService.getByDeviceId(deviceId);
        if (config == null || !Boolean.TRUE.equals(config.getIsEnabled())) {
            return;
        }

        // 获取最终使用的规则列表
        List<AlarmThresholdRule> rules = getEffectiveRules(config);

        for (AlarmThresholdRule rule : rules) {
            try {
                checkRuleAndAlert(deviceId, rule, config.getFamilyId());
            } catch (Exception e) {
                log.error("检测规则失败: device={}, rule={}", deviceId, rule.getAlarmType(), e);
            }
        }
    }

    /**
     * 获取设备最终生效的报警规则（模板 + 覆盖）
     */
    private List<AlarmThresholdRule> getEffectiveRules(DeviceAlarmConfig config) {
        List<AlarmThresholdRule> rules;

        // 1. 获取模板规则
        if (config.getTemplateId() != null) {
            AlarmThresholdTemplate template = alarmThresholdTemplateService.getByTemplateId(config.getTemplateId());
            if (template != null) {
                rules = new ArrayList<>(alarmThresholdRuleService.getByTemplateId(template.getId()));
            } else {
                rules = new ArrayList<>();
            }
        } else {
            rules = new ArrayList<>();
        }

        // 2. 应用覆盖规则（JSON解析）
        String overrideJson = config.getOverrideRules();
        if (overrideJson == null || overrideJson.trim().isEmpty()) {
            return rules;
        }

        try {
            // 解析 JSON：Map<AlarmType, OverrideDTO>
            Map<String, JsonNode> overrideMap = objectMapper.readValue(
                    overrideJson.trim(),
                    new TypeReference<Map<String, JsonNode>>() {
                    }
            );

            // 遍历覆盖项
            for (Map.Entry<String, JsonNode> entry : overrideMap.entrySet()) {
                String alarmTypeStr = entry.getKey();
                JsonNode overrideNode = entry.getValue();

                // 解析 alarmType
                AlarmType alarmType;
                try {
                    alarmType = AlarmType.of(alarmTypeStr);
                } catch (IllegalArgumentException e) {
                    log.warn("无效的 alarmType: {}，忽略覆盖", alarmTypeStr);
                    continue;
                }

                // 查找匹配的规则
                Optional<AlarmThresholdRule> targetOpt = rules.stream()
                        .filter(r -> r.getAlarmType() == alarmType)
                        .findFirst();

                if (targetOpt.isEmpty()) {
                    log.debug("设备 {} 的 overrideRules 中包含未匹配的 alarmType: {}", config.getDeviceId(), alarmTypeStr);
                    continue;
                }

                AlarmThresholdRule rule = targetOpt.get();

                // --- 开始覆盖字段 ---

                // 覆盖 thresholdValue
                if (overrideNode.has("thresholdValue")) {
                    JsonNode valNode = overrideNode.get("thresholdValue");
                    if (valNode.isTextual() || valNode.isNumber()) {
                        rule.setThresholdValue(valNode.asText());
                    }
                }

                // 覆盖 comparisonOp
                if (overrideNode.has("comparisonOp")) {
                    JsonNode opNode = overrideNode.get("comparisonOp");
                    if (opNode.isTextual()) {
                        String opStr = opNode.asText().trim().toUpperCase();
                        try {
                            ComparisonOperator op = ComparisonOperator.of(opStr);
                            rule.setComparisonOp(op);
                        } catch (IllegalArgumentException e) {
                            log.warn("设备 {} 的 alarmType={} 的 comparisonOp 无效: {}", config.getDeviceId(), alarmTypeStr, opStr);
                        }
                    }
                }

                // 覆盖 enabled
                if (overrideNode.has("enabled")) {
                    JsonNode enabledNode = overrideNode.get("enabled");
                    if (enabledNode.isBoolean()) {
                        rule.setIsEnabled(enabledNode.asBoolean());
                    } else if (enabledNode.isTextual()) {
                        rule.setIsEnabled(Boolean.parseBoolean(enabledNode.asText()));
                    }
                }

                // 覆盖 durationSec
                if (overrideNode.has("durationSec")) {
                    JsonNode node = overrideNode.get("durationSec");
                    if (node.canConvertToInt()) {
                        rule.setDurationSec(node.asInt());
                    }
                }

                // 覆盖 cooldownSec
                if (overrideNode.has("cooldownSec")) {
                    JsonNode node = overrideNode.get("cooldownSec");
                    if (node.canConvertToInt()) {
                        rule.setCooldownSec(node.asInt());
                    }
                }

                // 可扩展：覆盖 alarmLevel, description 等
                // if (overrideNode.has("alarmLevel")) { ... }

            } // end for

        } catch (Exception e) {
            log.error("解析设备 {} 的 overrideRules 失败: {}", config.getDeviceId(), overrideJson, e);
            // 解析失败不中断主流程，返回原始规则
        }

        return rules;
    }

    private void checkRuleAndAlert(String deviceId, AlarmThresholdRule rule, String familyId) {
        // 1. 判断是否启用
        if (!Boolean.TRUE.equals(rule.getIsEnabled())) {
            return;
        }

        // 2. 获取当前状态
        AlarmState state = alarmStateService.getState(deviceId, rule.getAlarmType());
        long now = System.currentTimeMillis();

        // 3. 判断是否超标
        String metricField = rule.getMetricField();
        EquipmentDataType equipmentDataType = EquipmentDataType.of(metricField);
        DataType dataType = equipmentDataType != null ? equipmentDataType.getDataType() : null;

        // 查询最新数据
        DeviceInstance device = deviceInstanceService.getById(deviceId);
        if (device == null) return;
        Object latestValue = deviceDataCollectionWideService.getLatestByDeviceId(device.getAutoId(), metricField);
        if (latestValue == null) return;
        String currentValueStr = latestValue.toString();

        // 比较当前值是否超出阈值
        boolean isExceeded = DeviceAlarmEvaluator.isValueExceeded(dataType, latestValue, rule.getThresholdValue(), rule.getComparisonOp());
        if (isExceeded) {
            // 更新首次超标时间
            if (state == null) {
                state = new AlarmState();
                state.setFirstExceedTimestamp(now);
            } else if (state.getFirstExceedTimestamp() == null) {
                state.setFirstExceedTimestamp(now);
            }

            // 检查是否满足持续时间
            boolean durationMet = checkDuration(now, state, rule.getDurationSec());

            // 检查是否在冷却期
            boolean inCooldown = checkCooldown(now, state, rule.getCooldownSec());

            if (durationMet && !inCooldown) {
                // 触发报警（注意：thresholdValue 可能是单值或 min,max）
                saveAlarmAndNotify(deviceId, rule, currentValueStr, rule.getThresholdValue(), familyId);
                state.setLastAlarmTimestamp(now); // 更新最后报警时间
            }
        } else {
            // 未超标：重置状态
            if (state != null) {
                state.setFirstExceedTimestamp(null); // 重置持续计时
            }
        }

        // 4. 保存最新状态
        if (state != null) {
            state.setCurrentValue(latestValue);
            state.setThresholdValue(rule.getThresholdValue());
        } else {
            state = AlarmState.builder()
                    .currentValue(latestValue)
                    .thresholdValue(rule.getThresholdValue())
                    .build();
        }
        alarmStateService.saveState(deviceId, rule.getAlarmType(), state);
    }

//    private Object queryLatestValue(String table, String deviceId, String field) {
//        return switch (table) {
//            case "device_readings_circuit_breaker" -> {
//                DeviceReadingCircuitBreaker cb = deviceReadingCircuitBreakerService.getLatestByDeviceId(deviceId);
//                if (cb == null) {
//                    yield null;
//                }
//                yield switch (field) {
//                    case "voltage" -> cb.getVoltage();
//                    case "current" -> cb.getCurrent();
//                    case "power" -> cb.getPower();
//                    case "energy_today" -> cb.getEnergyToday();
//                    case "power_factor" -> cb.getPowerFactor();
//                    default -> null;
//                };
//            }
//            case "device_readings_environment" -> {
//                DeviceReadingEnvironment env = deviceReadingEnvironmentService.getLatestByDeviceId(deviceId);
//                if (env == null) {
//                    yield null;
//                }
//                yield switch (field) {
//                    case "temperature" -> env.getTemperature();
//                    case "humidity" -> env.getHumidity();
//                    case "smoke_detected" -> env.getSmokeDetected();
//                    case "co_level" -> env.getCoLevel();
//                    case "pm25" -> env.getPm25();
//                    case "noise_level" -> env.getNoiseLevel();
//                    default -> null;
//                };
//            }
//            default -> null;
//        };
//    }

    private boolean checkDuration(long now, AlarmState state, Integer durationSec) {
        if (durationSec == null || durationSec <= 0) return true;
        Long first = state.getFirstExceedTimestamp();
        return first != null && (now - first) >= (durationSec * 1000L);
    }

    private boolean checkCooldown(long now, AlarmState state, Integer cooldownSec) {
        if (cooldownSec == null || cooldownSec <= 0) return false;
        Long last = state.getLastAlarmTimestamp();
        return last != null && (now - last) < (cooldownSec * 1000L);
    }

    private void saveAlarmAndNotify(String deviceId, AlarmThresholdRule rule, String currentValue, String thresholdValue, String familyId) {
        DeviceInstance deviceInstance = deviceInstanceService.queryDeviceInstance(deviceId);

        // 构建报警消息
        String alarmMessage = buildAlarmMessage(rule, deviceInstance, currentValue);

        // 创建报警
        DeviceAlarm alarm = deviceAlarmService.create(DeviceAlarmCreateReqDTO.builder()
                .deviceId(deviceId)
                .deviceType(deviceInstance != null && deviceInstance.getDeviceType() != null ? deviceInstance.getDeviceType().getCode() : "未知类型")
                .alarmType(rule.getAlarmType().getCode())
                .alarmLevel(rule.getAlarmLevel().getCode())
                .alarmMessage(alarmMessage)
                .triggerValue(currentValue)
                .thresholdValue(thresholdValue)
                .ruleId(rule.getId())
                .durationSec(rule.getDurationSec())
                .orgId(rule.getOrgId())
                .familyId(familyId)
                .build());
        if (alarm == null) {
            return;
        }

        // 创建通知
        List<String> recipientIds = new ArrayList<>();
        if (hasText(rule.getOrgId())) {
            recipientIds.add(rule.getOrgId());
        }
        Family family = sysFeignService.getFamilyById(alarm.getFamilyId());
        if (family != null) {
            recipientIds = List.of(family.getFamilyMembers().split(","));
        }
        if (recipientIds.isEmpty()) {
            return;
        }
        deviceAlarmNotificationService.create(recipientIds.stream()
                .map(member -> DeviceAlarmNotificationCreateReqDTO.builder()
                        .deviceAlarmId(alarm.getId())
                        .recipientId(member)
                        .notificationType(NotificationType.IN_SYSTEM)
                        .content(alarmMessage)
                        .orgId(alarm.getOrgId())
                        .familyId(alarm.getFamilyId())
                        .build())
                .toList());
    }

    private String buildAlarmMessage(AlarmThresholdRule rule, DeviceInstance device, String currentValue) {
        // 1. 获取模板
        AlarmThresholdTemplate template = alarmThresholdTemplateService.getByTemplateId(rule.getTemplateId());
        String messageTemplate = template != null && hasText(template.getMessageTemplate())
                ? template.getMessageTemplate()
                : "设备 {deviceName} 触发 {alarmLevel} 级报警";

        // 2. 提取参数
        Map<String, Object> params = alarmMessageParameterExtractor.extractParameters(rule, device, currentValue, LocalDateTime.now());

        // 3. 生成最终消息
        String alarmMessage = AlarmMessageFormatter.format(messageTemplate, params);

        return alarmMessage;
    }
}